home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / mail / vacation / vacation.c < prev   
C/C++ Source or Header  |  1988-04-25  |  7KB  |  349 lines

  1. /*
  2.  * Copyright (c) 1983, 1987 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. char copyright[] =
  15. "@(#) Copyright (c) 1983, 1987 Regents of the University of California.\n\
  16.  All rights reserved.\n";
  17. #endif /* not lint */
  18.  
  19. #ifndef lint
  20. static char sccsid[] = "@(#)vacation.c    5.9 (Berkeley) 3/24/88";
  21. #endif /* not lint */
  22.  
  23. /*
  24. **  Vacation
  25. **  Copyright (c) 1983  Eric P. Allman
  26. **  Berkeley, California
  27. */
  28.  
  29. #include <sys/param.h>
  30. #include <sys/file.h>
  31. #include <pwd.h>
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <syslog.h>
  35.  
  36. /*
  37. **  VACATION -- return a message to the sender when on vacation.
  38. **
  39. **    This program could be invoked as a message receiver when someone is
  40. **    on vacation.  It returns a message specified by the user to whoever
  41. **    sent the mail, taking care not to return a message too often to
  42. **    prevent "I am on vacation" loops.
  43. */
  44.  
  45. #define    MAXLINE    500            /* max line from mail header */
  46. #define    PERIOD    (60L*60L*24L*7L)    /* week between notifications */
  47. #define    VMSG    ".vacation.msg"        /* vacation message */
  48. #define    VACAT    ".vacation"        /* dbm's database prefix */
  49. #define    VDIR    ".vacation.dir"        /* dbm's DB prefix, part 1 */
  50. #define    VPAG    ".vacation.pag"        /* dbm's DB prefix, part 2 */
  51.  
  52. typedef struct alias {
  53.     struct alias *next;
  54.     char    *name;
  55. } ALIAS;
  56. ALIAS    *names;
  57.  
  58. static char from[MAXLINE];        /* sender's address */
  59.  
  60. main(argc, argv)
  61.     int argc;
  62.     char **argv;
  63. {
  64.     extern int optind;
  65.     extern char *optarg;
  66.     struct passwd *pw;
  67.     ALIAS *cur;
  68.     int ch, iflag;
  69.     char *malloc();
  70.     uid_t getuid();
  71.  
  72.     iflag = 0;
  73.     while ((ch = getopt(argc, argv, "a:Ii")) != EOF)
  74.         switch((char)ch) {
  75.         case 'a':            /* alias */
  76.             if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
  77.                 break;
  78.             cur->name = optarg;
  79.             cur->next = names;
  80.             names = cur;
  81.             break;
  82.         case 'i':            /* init the database */
  83.         case 'I':            /* backward compatible */
  84.             iflag = 1;
  85.             break;
  86.         case '?':
  87.         default:
  88.             goto usage;
  89.         }
  90.     argc -= optind;
  91.     argv += optind;
  92.  
  93.     if (argc != 1) {
  94.         if (!iflag) {
  95. usage:            syslog(LOG_ERR, "uid %u: usage: vacation [-i] [-a alias] login\n", getuid());
  96.             exit(1);
  97.         }
  98.         if (!(pw = getpwuid(getuid()))) {
  99.             syslog(LOG_ERR, "vacation: no such user uid %u.\n", getuid());
  100.             exit(1);
  101.         }
  102.     }
  103.     else if (!(pw = getpwnam(*argv))) {
  104.         syslog(LOG_ERR, "vacation: no such user %s.\n", *argv);
  105.         exit(1);
  106.     }
  107.     if (chdir(pw->pw_dir)) {
  108.         syslog(LOG_ERR, "vacation: no such directory %s.\n", pw->pw_dir);
  109.         exit(1);
  110.     }
  111.  
  112.     if (iflag) {
  113.         initialize();
  114.         exit(0);
  115.     }
  116.  
  117.     if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
  118.         exit(1);
  119.     cur->name = pw->pw_name;
  120.     cur->next = names;
  121.     names = cur;
  122.  
  123.     readheaders();
  124.  
  125.     if (access(VDIR, F_OK))
  126.         initialize();
  127.     else
  128.         dbminit(VACAT);
  129.  
  130.     if (!recent()) {
  131.         setreply();
  132.         sendmessage(pw->pw_name);
  133.     }
  134.     exit(0);
  135. }
  136.  
  137. /*
  138.  * readheaders --
  139.  *    read mail headers
  140.  */
  141. static
  142. readheaders()
  143. {
  144.     register ALIAS *cur;
  145.     register char *p;
  146.     int tome, cont;
  147.     char buf[MAXLINE], *strcpy(), *index();
  148.  
  149.     cont = tome = 0;
  150.     while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
  151.         switch(*buf) {
  152.         case 'F':        /* "From " */
  153.             cont = 0;
  154.             if (!strncmp(buf, "From ", 5)) {
  155.                 for (p = buf + 5; *p && *p != ' '; ++p);
  156.                 *p = '\0';
  157.                 (void)strcpy(from, buf + 5);
  158.                 if (junkmail())
  159.                     exit(0);
  160.             }
  161.             break;
  162.         case 'P':        /* "Precedence:" */
  163.             cont = 0;
  164.             if (strncasecmp(buf, "Precedence", 10) || buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t')
  165.                 break;
  166.             if (!(p = index(buf, ':')))
  167.                 break;
  168.             while (*++p && isspace(*p));
  169.             if (!*p)
  170.                 break;
  171.             if (!strncasecmp(p, "junk", 4) || !strncasecmp(p, "bulk", 4))
  172.                 exit(0);
  173.             break;
  174.         case 'C':        /* "Cc:" */
  175.             if (strncmp(buf, "Cc:", 3))
  176.                 break;
  177.             cont = 1;
  178.             goto findme;
  179.         case 'T':        /* "To:" */
  180.             if (strncmp(buf, "To:", 3))
  181.                 break;
  182.             cont = 1;
  183.             goto findme;
  184.         default:
  185.             if (!isspace(*buf) || !cont || tome) {
  186.                 cont = 0;
  187.                 break;
  188.             }
  189. findme:            for (cur = names; !tome && cur; cur = cur->next)
  190.                 tome += nsearch(cur->name, buf);
  191.         }
  192.     if (!tome)
  193.         exit(0);
  194.     if (!*from) {
  195.         syslog(LOG_ERR, "vacation: no initial \"From\" line.\n");
  196.         exit(1);
  197.     }
  198. }
  199.  
  200. /*
  201.  * nsearch --
  202.  *    do a nice, slow, search of a string for a substring.
  203.  */
  204. static
  205. nsearch(name, str)
  206.     register char *name, *str;
  207. {
  208.     register int len;
  209.  
  210.     for (len = strlen(name); *str; ++str)
  211.         if (*str == *name && !strncasecmp(name, str, len))
  212.             return(1);
  213.     return(0);
  214. }
  215.  
  216. /*
  217.  * junkmail --
  218.  *    read the header and return if automagic/junk/bulk mail
  219.  */
  220. static
  221. junkmail()
  222. {
  223.     static struct ignore {
  224.         char    *name;
  225.         int    len;
  226.     } ignore[] = {
  227.         "-REQUEST", 8,    "Postmaster", 10,
  228.         "uucp", 4,    "MAILER-DAEMON", 13,
  229.         "MAILER", 6,    NULL, NULL,
  230.     };
  231.     register struct ignore *cur;
  232.     register int len;
  233.     register char *p;
  234.     char *index(), *rindex();
  235.  
  236.     /*
  237.      * This is mildly amusing, and I'm not positive it's right; trying
  238.      * to find the "real" name of the sender, assuming that addresses
  239.      * will be some variant of:
  240.      *
  241.      * From site!site!SENDER%site.domain%site.domain@site.domain
  242.      */
  243.     if (!(p = index(from, '%')))
  244.         if (!(p = index(from, '@'))) {
  245.             if (p = rindex(from, '!'))
  246.                 ++p;
  247.             else
  248.                 p = from;
  249.             for (; *p; ++p);
  250.         }
  251.     len = p - from;
  252.     for (cur = ignore; cur->name; ++cur)
  253.         if (len >= cur->len && !strncasecmp(cur->name, p - cur->len, cur->len))
  254.             return(1);
  255.     return(0);
  256. }
  257.  
  258. typedef struct {
  259.     char    *dptr;
  260.     int    dsize;
  261. } DATUM;
  262.  
  263. typedef struct {
  264.     time_t    sentdate;
  265. } DBREC;
  266.  
  267. /*
  268.  * recent --
  269.  *    find out if user has gotten a vacation message recently.
  270.  */
  271. static
  272. recent()
  273. {
  274.     DATUM k, d, fetch();
  275.     time_t now, then, time();
  276.  
  277.     k.dptr = from;
  278.     k.dsize = strlen(from) + 1;
  279.     d = fetch(k);
  280.     if (d.dptr) {
  281.         /* be careful on machines with alignment restrictions */
  282.         bcopy((char *)&((DBREC *)d.dptr)->sentdate, (char *)&then, sizeof(then));
  283.         (void)time(&now);
  284.         if (!then || then + PERIOD > now)
  285.             return(1);
  286.     }
  287.     return(0);
  288. }
  289.  
  290. /*
  291.  * setreply --
  292.  *    store that this user knows about the vacation.
  293.  */
  294. static
  295. setreply()
  296. {
  297.     DBREC xrec;
  298.     DATUM k, d;
  299.     time_t time();
  300.  
  301.     k.dptr = from;
  302.     k.dsize = strlen(from) + 1;
  303.     (void)time(&xrec.sentdate);
  304.     d.dptr = (char *)&xrec;
  305.     d.dsize = sizeof(xrec);
  306.     store(k, d);
  307. }
  308.  
  309. /*
  310.  * sendmessage --
  311.  *    exec sendmail to send the vacation file to sender
  312.  */
  313. static
  314. sendmessage(myname)
  315.     char *myname;
  316. {
  317.     if (!freopen(VMSG, "r", stdin)) {
  318.         syslog(LOG_ERR, "vacation: no ~%s/%s file.\n", myname, VMSG);
  319.         exit(1);
  320.     }
  321.     execl("/usr/lib/sendmail", "sendmail", "-f", myname, from, NULL);
  322.     syslog(LOG_ERR, "vacation: can't exec /usr/lib/sendmail.\n");
  323.     exit(1);
  324. }
  325.  
  326. /*
  327.  * initialize --
  328.  *    initialize the dbm database
  329.  */
  330. static
  331. initialize()
  332. {
  333.     extern int errno;
  334.     extern char *sys_errlist[];
  335.     int fd;
  336.  
  337.     if ((fd = open(VDIR, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
  338.         syslog(LOG_ERR, "vacation: %s: %s\n", VDIR, sys_errlist[errno]);
  339.         exit(1);
  340.     }
  341.     (void)close(fd);
  342.     if ((fd = open(VPAG, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
  343.         syslog(LOG_ERR, "vacation: %s: %s\n", VPAG, sys_errlist[errno]);
  344.         exit(1);
  345.     }
  346.     (void)close(fd);
  347.     dbminit(VACAT);
  348. }
  349.